/** @file    Method.cpp
 *  @author  Alessandro Polo
 *  @version $Id: Method.cpp 2827 2010-08-02 11:01:48Z alex $
 *  @brief
 * File containing methods for the wosh::Method class.
 * The header for this class can be found in Method.h, check that file
 * for class description.
 ****************************************************************************/
/* Copyright (c) 2007-2010, WOSH - Wide Open Smart Home 
 * by Alessandro Polo - OpenSmartHome.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the OpenSmartHome.com WOSH nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Alessandro Polo ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Alessandro Polo BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ****************************************************************************/

 #include <core/Method.h>

 #include <core/ObjectAllocator.h>
 #include <core/DataModels.h>


using namespace std;
namespace wosh {

multimap<string, Method*> MethodCollector::Methods;
MutexRW MethodCollector::MethodsMux;

const Permission Method::defaultPermission;

 WOSH_REGISTER_INTERFACE(wosh::Method, "", 1.00, _static_Method )

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////// CONSTRUCTORS

Method::Method( const std::string& Name ) {
	this->global = false;
	clear();
	this->name = Name;
 }

Method::Method( const std::string& Name, const std::string& descr, const Permission& perm ) {
	this->global = false;
	clear();

	this->name = Name;
	this->description = descr;
	this->permission = perm;
 }

Method::Method( const Method& m ) {
	this->global = false;
	clear();

	this->name = m.name;
	this->description = m.description;
	this->permission = m.permission;
	this->arguments = m.arguments;
 }

Method::~Method() {
	if ( this->global )
		unRegisterGlobal();
 }

//////////////////////////////////////////////////////////////////////////////////////////////// CONSTRUCTORS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////// SERVICE CONTROL

void Method::clear() {
	this->name = "";
	this->description = "";
	this->permission.setMask( Permission::RX, Permission::RX, Permission::RX );
	this->arguments.clear();
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

std::string Method::toStringUnixStyle() const {
	return this->permission.toUnixStyle() + "\t" + this->name + "\t\t" + this->description;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void Method::registerGlobal( const URI& ownerUri ) {
	this->global = true;
	this->ownerReference = ownerUri;
	MutexLockerWrite mL(&MethodCollector::MethodsMux);
	MethodCollector::Methods.insert( std::pair<std::string, Method*>(this->getName(),this) );
 }

void Method::unRegisterGlobal() {
	this->global = false;
	MutexLockerWrite mL(&MethodCollector::MethodsMux);
	std::multimap<std::string, Method*>::iterator it;
	for ( it=MethodCollector::Methods.begin(); it!=MethodCollector::Methods.end(); ++it ) {
		if ( it->second != this ) continue;
		MethodCollector::Methods.erase(it);
		return;
	 }
 }
 
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

DataFieldCollector<Method>* Method::getDataFields() {
	DataFieldCollector<Method>* fields = new DataFieldCollector<Method>();
	fields->add<const std::string&, Variant>(&Method::getName, "Name", 0);
	fields->add<const char*, Variant>(&Method::getClassName, "Type", 1);
	fields->add<const std::string&,Variant>(&Method::getDescription, "Description", 2);
	fields->add<const Permission&,Permission>(&Method::getPermission, "Permission", 3);
	DataFieldSubWrapperT<Method, const MethodArguments&, std::string, Variant>* dfwMethodArgumentsStr;
	dfwMethodArgumentsStr = new DataFieldSubWrapperT<Method, const MethodArguments&, std::string, Variant>(&Method::getArguments, &MethodArguments::toString, "Arguments[Str]", 4);
	dfwMethodArgumentsStr->info.visible = false;
	fields->add(dfwMethodArgumentsStr);
	return fields;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

const char* GenericErrorDescriptionStr[] = {
	"description not available",
	"missing/invalid/illegal parameter(s)",	
	"internal (routine) error",
	"illegal use of function (forbidden)",
	"method is deprecated",
	"call is not valid in current state",
	"unknown (not handled) error",
	"security/permission error",
	"not implemented",
 };


const char* Method::getGenericErrorDescription( WRESULT retcode ) {
	switch( retcode ) {
		case WRET_ERR_PARAM:		return GenericErrorDescriptionStr[1];
		case WRET_ERR_INTERNAL:		return GenericErrorDescriptionStr[2];
		case WRET_ERR_ILLEGAL_USE:	return GenericErrorDescriptionStr[3];
		case WRET_ERR_DEPRECATED:	return GenericErrorDescriptionStr[4];
		case WRET_ERR_WRONG_STATE:	return GenericErrorDescriptionStr[5];
		case WRET_ERR_UNKNOWN:		return GenericErrorDescriptionStr[6];
		case WRET_ERR_SECURITY:		return GenericErrorDescriptionStr[7];
		case WRET_NOT_IMPLEMENTED:	return GenericErrorDescriptionStr[8];
		default:					return GenericErrorDescriptionStr[0];
	 }
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

long MethodCollector::exists( const Method* method ) {
	if ( method == NULL ) return false;
	MutexLockerRead mL(&MethodCollector::MethodsMux);
	std::multimap<std::string, Method*>::const_iterator it;
	for ( it=MethodCollector::Methods.begin(); it!=MethodCollector::Methods.end(); ++it ) {
		if ( it->second != method ) continue;
		return true;
	 }
	return false;
 }

long MethodCollector::exists( const std::string method_name ) {
	if ( method_name.empty() ) return false;
	MutexLockerRead mL(&MethodCollector::MethodsMux);
	return MethodCollector::Methods.count("a");
 }

Method* MethodCollector::get( const std::string method_name ) {
	if ( method_name.empty() ) return false;
	MutexLockerRead mL(&MethodCollector::MethodsMux);
	std::multimap<std::string, Method*>::const_iterator it;
	for ( it=MethodCollector::Methods.begin(); it!=MethodCollector::Methods.end(); ++it ) {
		if ( it->second == NULL ) continue;
		if ( it->first != method_name ) continue;
		return it->second;
	 }
	return NULL;
 }

int MethodCollector::gets( std::vector<Method*>& results, const std::string method_name, bool ) {
	if ( method_name.empty() ) return results.size();
	MutexLockerRead mL(&MethodCollector::MethodsMux);
	std::multimap<std::string, Method*>::const_iterator it;
	for ( it=MethodCollector::Methods.begin(); it!=MethodCollector::Methods.end(); ++it ) {
		if ( it->second == NULL ) continue;
		if ( it->first != method_name ) continue;
		results.push_back(it->second);
	 }
	return results.size();
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

int MethodCollector::getList( std::vector<std::string>& output_list ) {
	MutexLockerRead mL(&MethodCollector::MethodsMux);
	std::multimap<std::string, Method*>::const_iterator it;
	for ( it=MethodCollector::Methods.begin(); it!=MethodCollector::Methods.end(); ++it ) {
		if ( it->second == NULL ) continue;
		output_list.push_back( it->first );
	 }
	return output_list.size();
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

}; // namespace wosh
